package com.vhall.component.service.tag.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vhall.component.dao.room.RoomMapper;
import com.vhall.component.dao.tag.AdvertisingMapper;
import com.vhall.component.entity.dictionary.enums.AdTypeEnum;
import com.vhall.component.entity.dictionary.enums.PlacementLocationEnum;
import com.vhall.component.entity.page.vo.PageVO;
import com.vhall.component.entity.room.entity.RoomsEntity;
import com.vhall.component.entity.room.enums.RoomAuditStatusEnum;
import com.vhall.component.entity.tag.AdvertisingEntity;
import com.vhall.component.entity.tag.enums.AdverShelvesEnum;
import com.vhall.component.entity.tag.vo.AdvertisingChangeReqVO;
import com.vhall.component.entity.tag.vo.AdvertisingListReqVO;
import com.vhall.component.entity.tag.vo.AdvertisingListRspVO;
import com.vhall.component.entity.tag.vo.AdvertisingReqVO;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.framework.common.utils.CollectionUtils;
import com.vhall.component.plugin.common.enums.DeleteStatusEnum;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.utils.BeanCopyUtil;
import com.vhall.component.service.account.BaseUserPermissionService;
import com.vhall.component.service.common.BaseCommonService;
import com.vhall.component.service.tag.AdvertisingService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Preconditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.List;

import static com.vhall.component.plugin.common.constant.RedisKey.REGULAR_DOWN_ADVER_TASK;
import static com.vhall.component.plugin.common.constant.RedisKey.REGULAR_DOWN_ADVER_TASK_LIST;

/**
 * @author vhall
 * @description 针对表【advertising(广告表)】的数据库操作Service实现
 * @createDate 2023-04-11 19:00:30
 */
@Slf4j
@Service
public class AdvertisingServiceImpl extends BaseUserPermissionService implements AdvertisingService {

    @Resource
    private AdvertisingMapper advertisingMapper;

    @Resource
    private RoomMapper roomMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Resource
    private BaseCommonService baseCommonService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(AdvertisingReqVO vo) {

        basicValidate(vo);

        assemblySort(vo);

        LocalDateTime start = LocalDateTimeUtil.parse(vo.getStartTime(), DatePattern.NORM_DATETIME_PATTERN);
        LocalDateTime end = LocalDateTimeUtil.parse(vo.getEndTime(), DatePattern.NORM_DATETIME_PATTERN);
        LocalDateTime now = LocalDateTime.now();

        AdvertisingEntity advertisingEntity = new AdvertisingEntity();
        BeanCopyUtil.copy(vo, advertisingEntity);

        addUserInfo(advertisingEntity);

        advertisingEntity.setStartTime(start);
        advertisingEntity.setEndTime(end);

        // 根据时间判断当前状态

        Integer isShelves = getIsShelves(start, end, now);
        advertisingEntity.setIsShelves(isShelves);

        advertisingMapper.insert(advertisingEntity);

        redisTemplate.opsForSet().add(REGULAR_DOWN_ADVER_TASK_LIST, advertisingEntity.getId());
        redisTemplate.opsForValue().set(REGULAR_DOWN_ADVER_TASK + advertisingEntity.getId(), JSON.toJSON(advertisingEntity));

        return true;
    }

    private void assemblySort(AdvertisingReqVO vo) {
        Integer sort = vo.getSort();
        LambdaQueryWrapper<AdvertisingEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(AdvertisingEntity::getIsDelete, DeleteStatusEnum.NO_DELETE.getStatus());
        wrapper.ge(AdvertisingEntity::getSort, sort);
        wrapper.orderByAsc(AdvertisingEntity::getSort);
        List<AdvertisingEntity> entities = advertisingMapper.selectList(wrapper);

        if (CollectionUtils.isNotEmpty(entities)) {
            for (int i = 0; i < entities.size(); i++) {
                AdvertisingEntity advertisingEntity = entities.get(i);
                if (advertisingEntity.getSort().equals(sort)
                        && (vo.getId() == null || !vo.getId().equals(advertisingEntity.getId()))) {
                    sort = sort + 1;
                    advertisingEntity.setSort(sort);
                    advertisingMapper.updateById(advertisingEntity);
                }
            }
        }
    }

    @Override
    public PageVO<AdvertisingListRspVO> list(AdvertisingListReqVO vo) {

        LocalDateTime beginTime = null;
        if (StringUtils.isNotBlank(vo.getStartTime())) {
            beginTime = DateUtil.parseLocalDateTime(vo.getStartTime(), DatePattern.NORM_DATE_PATTERN);
            beginTime = beginTime.truncatedTo(ChronoUnit.DAYS);
        }

        LocalDateTime endTime = null;
        if (StringUtils.isNotBlank(vo.getEndTime())) {
            endTime = DateUtil.parseLocalDateTime(vo.getEndTime(), DatePattern.NORM_DATE_PATTERN);
            endTime = endTime.with(LocalTime.MAX);
        }


        LambdaQueryWrapper<AdvertisingEntity> where = Wrappers.lambdaQuery();
        where.eq(StringUtils.isNotBlank(getUserPermission()), AdvertisingEntity::getOrgCode, getUserPermission());
        where.and(StringUtils.isNotBlank(vo.getKeyword()), wq -> wq.eq(AdvertisingEntity::getIlId, vo.getKeyword()).or().like(AdvertisingEntity::getTitle, vo.getKeyword()));
        where.eq(AdvertisingEntity::getIsDelete, DeleteStatusEnum.NO_DELETE.getStatus());
        where.eq(vo.getIsShelves() != null, AdvertisingEntity::getIsShelves, vo.getIsShelves());
        where.ge(StringUtils.isNotBlank(vo.getStartTime()), AdvertisingEntity::getStartTime, beginTime)
                .le(StringUtils.isNotBlank(vo.getEndTime()), AdvertisingEntity::getEndTime, endTime);
        where.orderByAsc(AdvertisingEntity::getSort);

        Page<AdvertisingEntity> page = new Page<>(vo.getPage(), vo.getPageSize());
        Page<AdvertisingEntity> pages = advertisingMapper.selectPage(page, where);

        List<AdvertisingEntity> records = pages.getRecords();
        List<AdvertisingListRspVO> rspVOS = BeanCopyUtil.batchCopy(records, AdvertisingListRspVO::new);

        if (CollectionUtils.isNotEmpty(rspVOS)) {
            rspVOS.forEach(e -> e.setColumnName("发现"));
        }

        chineseAssignment(rspVOS);

        return new PageVO<>(vo.getPage(), vo.getPageSize(), (int) page.getTotal(), rspVOS);

    }

    /**
     * 中文赋值
     */
    private void chineseAssignment(List<AdvertisingListRspVO> rspVOS) {
        if (CollectionUtil.isNotEmpty(rspVOS)) {
            rspVOS.forEach(e -> {
                e.setPlacementLocationName(PlacementLocationEnum.getName(e.getPlacementLocation()));
                e.setAdTypeName(AdTypeEnum.getName(e.getAdType()));
                e.setIsShelvesName(AdverShelvesEnum.getName(e.getIsShelves()));
                baseCommonService.convertUrl(e, "image");
            });
        }

    }

    @Override
    public Boolean updateInfo(AdvertisingReqVO vo) {

        basicValidate(vo);
        Preconditions.checkArgument(vo.getId() != null, "id不能为空！");

        AdvertisingEntity entity = advertisingMapper.selectById(vo.getId());
        Preconditions.checkArgument(entity != null, "id传入有误！");

        checkUserPermission(entity.getOrgCode());


        assemblySort(vo);

        LocalDateTime start = LocalDateTimeUtil.parse(vo.getStartTime(), DatePattern.NORM_DATETIME_PATTERN);
        LocalDateTime end = LocalDateTimeUtil.parse(vo.getEndTime(), DatePattern.NORM_DATETIME_PATTERN);
        LocalDateTime now = LocalDateTime.now();

        LambdaUpdateWrapper<AdvertisingEntity> wrapper = new LambdaUpdateWrapper<>();

        wrapper.set(AdvertisingEntity::getPlacementLocation, vo.getPlacementLocation());
        wrapper.set(AdvertisingEntity::getAdType, vo.getAdType());
        wrapper.set(AdvertisingEntity::getTitle, StringUtils.isNotBlank(vo.getTitle()) ? vo.getTitle() : "");
        wrapper.set(AdvertisingEntity::getUrl, StringUtils.isNotBlank(vo.getUrl()) ? vo.getUrl() : "");
        wrapper.set(AdvertisingEntity::getSort, vo.getSort());
        wrapper.set(AdvertisingEntity::getStartTime, start);
        wrapper.set(AdvertisingEntity::getEndTime, end);
        wrapper.set(AdvertisingEntity::getImage, vo.getImage());
        wrapper.set(AdvertisingEntity::getIlId, vo.getIlId());

        // 根据时间判断当前状态
        Integer isShelves = getIsShelves(start, end, now);

        wrapper.set(AdvertisingEntity::getIsShelves, isShelves);

        wrapper.eq(AdvertisingEntity::getId, vo.getId());

        advertisingMapper.update(null, wrapper);

        entity.setStartTime(LocalDateTimeUtil.parse(vo.getStartTime(), DatePattern.NORM_DATETIME_PATTERN));
        entity.setEndTime(LocalDateTimeUtil.parse(vo.getEndTime(), DatePattern.NORM_DATETIME_PATTERN));


        redisTemplate.opsForSet().add(REGULAR_DOWN_ADVER_TASK_LIST, vo.getId());
        redisTemplate.opsForValue().set(REGULAR_DOWN_ADVER_TASK + vo.getId(), JSON.toJSON(entity));

        return true;
    }

    /**
     * 根据时间判断当前状态
     *
     * @param start 开始时间
     * @param end   结束时间
     * @param now   当前时间
     */
    private Integer getIsShelves(LocalDateTime start, LocalDateTime end, LocalDateTime now) {
        Integer isShelves;
        if (start.compareTo(now) > 0) {
            // 开始时间，大于当前时间
            isShelves = AdverShelvesEnum.NOT_LISTED.getValue();
        } else if (start.compareTo(now) == 0) {
            isShelves = AdverShelvesEnum.LISTED.getValue();
        } else {
            // 开始时间小于当前时间
            if (end.compareTo(now) > 0) {
                // 结束时间大于当前时间
                isShelves = AdverShelvesEnum.LISTED.getValue();
            } else if (end.compareTo(now) == 0) {
                // 结束时间等于当前时间
                isShelves = AdverShelvesEnum.REMOVED_FROM_SHELVES.getValue();
            } else {
                // 结束时间小于于当前时间
                isShelves = AdverShelvesEnum.REMOVED_FROM_SHELVES.getValue();
            }
        }
        log.info(MessageFormat.format("开始时间：【{0}】 结束时间：【{1}】 当前时间：【{2}】 状态：【{3}】"
                , LocalDateTimeUtil.format(start, DatePattern.NORM_DATE_PATTERN)
                , LocalDateTimeUtil.format(end, DatePattern.NORM_DATE_PATTERN)
                , LocalDateTimeUtil.format(now, DatePattern.NORM_DATE_PATTERN)
                , isShelves));

        return isShelves;
    }


    @Override
    public Boolean deleteInfo(Integer id) {

        AdvertisingEntity entity = advertisingMapper.selectById(id);
        Preconditions.checkArgument(entity != null, "id传入有误！");

        entity.setUpdatedAt(LocalDateTime.now());
        entity.setIsDelete(DeleteStatusEnum.DELETE.getStatus());
        advertisingMapper.updateById(entity);

        redisTemplate.opsForSet().remove(REGULAR_DOWN_ADVER_TASK_LIST, id);
        redisTemplate.delete(REGULAR_DOWN_ADVER_TASK + id);

        return true;
    }

    @Override
    public List<AdvertisingListRspVO> getInfo(List<Integer> ids) {
        List<AdvertisingEntity> advertisingEntities = advertisingMapper.selectBatchIds(ids);
        List<AdvertisingListRspVO> rspVos = BeanCopyUtil.batchCopy(advertisingEntities, AdvertisingListRspVO::new);
        if (CollectionUtils.isNotEmpty(rspVos)) {
            for (AdvertisingListRspVO rspVo : rspVos) {
                rspVo.setColumnName("发现");
            }
        }
        chineseAssignment(rspVos);
        return rspVos;
    }


    @Override
    public Boolean upAndDownShelves(AdvertisingChangeReqVO vo) {
        AdvertisingEntity entity = advertisingMapper.selectById(vo.getId());
        Preconditions.checkArgument(entity != null, "id传入有误！");

        if (vo.getIsShelves() == 0) {
            // 下架
            entity.setEndTime(LocalDateTime.now());
        } else {
            // 上架
            entity.setStartTime(LocalDateTime.now());
        }


        entity.setUpdatedAt(LocalDateTime.now());
        entity.setIsShelves(vo.getIsShelves());
        advertisingMapper.updateById(entity);

        redisTemplate.opsForSet().add(REGULAR_DOWN_ADVER_TASK_LIST, entity.getId());
        redisTemplate.opsForValue().set(REGULAR_DOWN_ADVER_TASK + entity.getId(), JSON.toJSON(entity));
        return true;
    }

    private void basicValidate(AdvertisingReqVO vo) {

        if (vo.getAdType().equals(AdTypeEnum.DIRECT_SEEDING.getValue())) {

            Preconditions.checkArgument(vo.getIlId() != null, "关联直播间不能为空！");
            RoomsEntity roomsEntity = getInfoByIlId(vo.getIlId());
            Preconditions.checkArgument(roomsEntity.getAuditStatus().equals(RoomAuditStatusEnum.APPROVED.getAuditStatus()), "当前直播间未审核通过！");
            if (StringUtils.isBlank(vo.getTitle())) {
                vo.setTitle(roomsEntity.getSubject());
            }

        } else {
            Preconditions.checkArgument(StringUtils.isNotBlank(vo.getTitle()), "广告标题不能为空！");
            Preconditions.checkArgument(StringUtils.isNotBlank(vo.getUrl()), "原生链接不能为空！");

        }

    }


    private RoomsEntity getInfoByIlId(Integer ilId) {
        RoomsEntity roomsEntity = roomMapper.selectById(ilId);
        if (roomsEntity == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        return roomsEntity;
    }
}
